package com.ryqg.jiaofu.web.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ryqg.jiaofu.business.common.PageResult;
import com.ryqg.jiaofu.business.common.Pdf2HtmlExConverter;
import com.ryqg.jiaofu.common.converter.PDFInfoConverter;
import com.ryqg.jiaofu.domain.pagequery.pdfinfo.*;
import com.ryqg.jiaofu.domain.pojo.PDFInfo;
import com.ryqg.jiaofu.domain.vo.OperationVO;
import com.ryqg.jiaofu.domain.vo.PDFInfoVO;
import com.ryqg.jiaofu.domain.vo.PopularPdfVO;
import com.ryqg.jiaofu.utils.OssClient;
import com.ryqg.jiaofu.web.mapper.PDFDropdownMapper;
import com.ryqg.jiaofu.web.mapper.PDFMapper;
import com.ryqg.jiaofu.web.service.PDFService;
import lombok.AllArgsConstructor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Comment;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;
import org.jsoup.parser.Parser;
import org.jsoup.select.NodeTraversor;
import org.jsoup.select.NodeVisitor;
import org.springframework.stereotype.Service;

import java.io.File;
import java.time.LocalDateTime;
import java.util.List;

@Service
@AllArgsConstructor
public class PDFServiceImpl implements PDFService {
    private static final String TMP_FILE_FOLDER = System.getProperty("java.io.tmpdir") + File.separator + "pdf" ;
    private static final String FILE_NAME = "index.html";
    private final PDFMapper pDFMapper;

    private final PDFInfoConverter pdfInfoConverter;

    private final PDFDropdownMapper pdfDropdownMapper;

    @Override
    public String getPDFView(String docId) {
        PDFInfo pdfInfo = pDFMapper.selectById(docId);
        String htmlKey = pdfInfo.getHtmlKey();
        AmazonS3 s3Client = OssClient.getS3Client();
        S3Object object = s3Client.getObject(OssClient.getPrivateBucket(), htmlKey);
        S3ObjectInputStream objectContent = object.getObjectContent();

        try {

            if (ObjectUtil.isNull(objectContent)) {
                try {
                    Pdf2HtmlExConverter converter = new Pdf2HtmlExConverter("D:\\Users\\caozh\\Downloads\\pdf2htmlEX-win32-0.14.6-with-poppler-data\\pdf2htmlEX.exe");
                    String folder = TMP_FILE_FOLDER + File.separator + docId;
                    converter.setFolder(folder);
                    converter.setFileName(FILE_NAME);
                    String filePath = folder + File.separator + FILE_NAME;
                    converter.convert("D:\\Users\\caozh\\Downloads\\pdftest\\※【期末复习易错系列】【期末易错题专项提升训练】五下数学.pdf");

                    Document parse = Jsoup.parse(new File(filePath), "utf-8", "", Parser.htmlParser());
                    parse.outputSettings().prettyPrint(false);
                    // 创建一个 NodeVisitor 来遍历节点

                    NodeVisitor visitor = new NodeVisitor() {
                        @Override
                        public void head(Node node, int depth) {
                            if (node instanceof Comment) {
                                node.remove();
                            }
                        }
                    };
                    NodeTraversor.traverse(visitor, parse);
                    parse.select("[id=sidebar]").remove();
                    parse.select("[id=page-container]").removeAttr("id").addClass("pdf-container");
                    parse.select("script").remove();
                    return parse.html();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                return new String(objectContent.readAllBytes());
            }
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
    /**
     *用于首页最新文档接口，展示最新的10条数据
     * */
    @Override
    public List<PDFInfoVO> getPDFList() {
        List<PDFInfo> pdfInfos =  pDFMapper.selectPDFList();

        return pdfInfoConverter.toVOList(pdfInfos);
    }


    /**
     *  用于首页热门文档，展示下载量最多的10条数据
     * */
    @Override
    public List<PopularPdfVO> popularPdfList(){
        return pDFMapper.popularPdfList();
    }

    /**
     * 获取用户动态
     * 用于首页用户动态，展示用户最近下载的操作10条数据
     * */
    @Override
    public List<OperationVO> userActivity(){
        List<OperationVO> operationVOList =  pDFMapper.userActivity();
        return operationVOList;
    }

    @Override
    public PageResult<PDFInfoVO> searchPDFList(PDFInfoPageQuery pdfInfoPageQuery) {
        Page<PDFInfo> page = Page.of(pdfInfoPageQuery.getPageNumber(), pdfInfoPageQuery.getPageSize());
        LambdaQueryWrapper<PDFInfo> wrapper = buildQueryWrapper(pdfInfoPageQuery);
        page = pDFMapper.selectPage(page,wrapper);
        return pdfInfoConverter.toPageResult(page);
    }

    private LambdaQueryWrapper<PDFInfo> buildQueryWrapper(PDFInfoPageQuery pdfInfoPageQuery) {
        LambdaQueryWrapper<PDFInfo> wrapper = Wrappers.lambdaQuery();
        // 先获取分类的父节点包括子
        if(StrUtil.isNotBlank(pdfInfoPageQuery.getClassifyId())){
            List<String> classifyIdList = pdfDropdownMapper.selectChildIncludeSelf(pdfInfoPageQuery.getClassifyId());
            wrapper.in(!classifyIdList.isEmpty(),PDFInfo::getClassifyId,classifyIdList);
        }

        // 页数筛选
        buildPageCountCondition(wrapper, pdfInfoPageQuery.getPageCount());

        // 时间筛选
        buildTimeRangeCondition(wrapper, pdfInfoPageQuery.getTimeRange());

        // 文档类型筛选
        buildDocTypeCondition(wrapper, pdfInfoPageQuery.getDocType());

        // 关键词搜索
        wrapper.like(StrUtil.isNotBlank(pdfInfoPageQuery.getKeyword()),
                PDFInfo::getName, pdfInfoPageQuery.getKeyword());

        // 排序
        buildOrderCondition(wrapper, pdfInfoPageQuery.getTab());

        return wrapper;
    }

    private void buildPageCountCondition(LambdaQueryWrapper<PDFInfo> wrapper, String pageCount) {
        PageCountEnum pageCountEnum = PageCountEnum.fromCode(pageCount);
        switch (pageCountEnum) {
            case PAGES_1_9:
                wrapper.between(PDFInfo::getTotalPage, 1, 9);
                break;
            case PAGES_10_19:
                wrapper.between(PDFInfo::getTotalPage, 10, 19);
                break;
            case PAGES_20_PLUS:
                wrapper.ge(PDFInfo::getTotalPage, 20);
                break;
            case ALL:
            default:
                // 不添加条件
                break;
        }
    }

    private void buildTimeRangeCondition(LambdaQueryWrapper<PDFInfo> wrapper, String timeRange) {
        TimeRangeEnum timeRangeEnum = TimeRangeEnum.fromCode(timeRange);
        LocalDateTime now = LocalDateTime.now();

        switch (timeRangeEnum) {
            case WEEK:
                wrapper.ge(PDFInfo::getCreateTime, now.minusWeeks(1));
                break;
            case MONTH:
                wrapper.ge(PDFInfo::getCreateTime, now.minusMonths(1));
                break;
            case QUARTER:
                wrapper.ge(PDFInfo::getCreateTime, now.minusMonths(3));
                break;
            case ALL:
            default:
                // 不添加条件
                break;
        }
    }

    private void buildDocTypeCondition(LambdaQueryWrapper<PDFInfo> wrapper, String docType) {
        DocPriEnum docTypeEnum = DocPriEnum.fromCode(docType);
        switch (docTypeEnum) {
            case VIP:
                wrapper.eq(PDFInfo::getPrivilege, 2);
                break;
            case VIP_FREE:
                wrapper.eq(PDFInfo::getPrivilege, 1);
                break;
            case FREE:
                wrapper.eq(PDFInfo::getPrivilege, 0);
                break;
            case ALL:
            default:
                // 不添加条件
                break;
        }
    }

    private void buildOrderCondition(LambdaQueryWrapper<PDFInfo> wrapper, String tab) {
        TabEnum tabEnum = TabEnum.fromCode(tab);
        switch (tabEnum) {
            case HOT_DOWNLOAD:
                wrapper.orderByDesc(PDFInfo::getDownloads);
                break;
            case VIEW_PRIORITY:
                wrapper.orderByDesc(PDFInfo::getViews);
                break;
            case COLLECT_PRIORITY:
                wrapper.orderByDesc(PDFInfo::getFavorites);
                break;
            case LATEST_UPLOAD:
            default:
                wrapper.orderByDesc(PDFInfo::getCreateTime);
                break;
        }
    }
}
